
#pragma once
#include<iostream>
#include<string.h>
#include <stdlib.h>
#include<memory>
#include <sys/types.h>
#include <sys/socket.h>
#include<strings.h>
#include<arpa/inet.h>
#include<netinet/in.h>
using namespace std;

namespace udpServer//接收端
{

static const string defaultIp="0.0.0.0";//默认的ip地址，
static const int gnum=1024;//缓存区大小

enum {USAGE_ERR=1,SOCKET_ERR,BIND_ERR,OPEN_ERR};//用枚举函数定义各自错误的返回值

class udpserver{
public:
udpserver(const uint16_t& port,const string&ip=defaultIp)
//外部需要传参回调函数，端口，ip地址进来初始化
//:_callback(func)
:_port(port)
,_ip(ip)
,_sockfd(-1)
{}

void initServer()
{
    //1.创建socket
    _sockfd=socket(AF_INET,SOCK_DGRAM,0);//创建socketfd，使用的协议是ipv4，套接字协议是UDP协议
    if(_sockfd==-1)
    {
        cout<<"socket error: "<<errno<<" : "<<strerror(errno)<<endl;
        exit(SOCKET_ERR);
    }
    cout<<"socket success"<<": "<< _sockfd<<endl;
//2.绑定相应的IP和port，作为发送端需要将数据发送到指定的ip和port
struct sockaddr_in local;//定义一个结构体
bzero(&local,sizeof(local));//将local结构体清零--需要将sever端的地址类型, 端口号, IP地址传入该结构体
local.sin_family=AF_INET;//地址类型
local.sin_port=htons(_port);//需要将本地类型的端口转化成网络序列
local.sin_addr.s_addr=inet_addr(_ip.c_str());
//local.sin_addr.s_addr=htonl(INADDR_ANY);//不设置ip地址即接收任意ip地址发送来的数据
//inet_addr函数作用：一是将string类型转化为uin32_t类型，二是将本地字节转化为网络字节顺序
int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
if(n==-1)
{
    cout<<"bind error: "<<errno<<" : "<<strerror(errno)<<endl;
        exit(BIND_ERR);
}

}

void start()
{
char buffer[gnum];//设置缓冲区
for(;;)
{
    struct sockaddr_in sockin;//建立结构体
    socklen_t  len=sizeof(sockin);
    ssize_t s=recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&sockin,&len);
    //套接字的数据保存到指定缓冲区中

if(s>0)
{
    buffer[s]=0;
    string clientip=inet_ntoa(sockin.sin_addr);//将网络字节转化成本地字节
    uint16_t clientport=ntohs(sockin.sin_port);//将网络字节转化成本地字节
    string mssage=buffer;
    
    cout<<"clientip: "<<clientip<<" [ "<<clientport<<" ]# "<<mssage<<endl;

  //  _callback()
}
}
}

~udpserver()
{}


private:
uint16_t _port;//端口
string _ip;//ip地址
int _sockfd;//套接字文件描述符
//func_t _callback;//回调函数类型

};


}
